Coursera week5
Neural Network(ニューラルネットワーク)実践編
ニューラルネットワークは、これまでの線形回帰やロジスティック回帰などのアルゴリズムに比べると、かなり複雑なものとなっています。そこで、まず最初に、実際に実装する手順を示し、そのあと、重要な技術について実装例とともに説明を加えていきたいと思います。
ニューラルネットワーク実装手順 -----------------------------------------------------------------
①重みの初期値をランダムに決めます。
②入力$ x^{(i)} から仮説関数$ h_\theta(x^{(i)}) を取得します(フォワードプロパゲーション)。
③目的関数を実装します。
④目的関数の最小値を求める(偏微分する)ために誤差逆伝播法(バックプロパゲーション)を実装します。
⑤誤差逆伝播法が正しく機能しているかを確認するために、Gradient Checkingを実装します。
------------------------------------------------------------------------------------------------------------------------------
①Random Initialization(ランダム初期化)
線形回帰やロジスティック回帰の時には、$ \theta の初期値をゼロにしていました。ですが、残念なことにそれはニューラルネットワークでは機能しません。 誤差逆伝播法を使用すると、すべてのノードが同じ値に繰り返し更新されてしまうためです。 代わりに、次の方法を使用して$ \theta 行列の重みをランダムに初期化することができます。
https://gyazo.com/52b7e21a4c26d234201996cfca186aab
code: Octave
% If the dimensions of Theta1 is 10x11, Theta2 is 10x11 and Theta3 is 1x11.
Theta1 = rand(10,11) * (2 * INIT_EPSILON) - INIT_EPSILON;
Theta2 = rand(10,11) * (2 * INIT_EPSILON) - INIT_EPSILON;
Theta3 = rand(1,11) * (2 * INIT_EPSILON) - INIT_EPSILON;
②Forwardpropagation(フォワードプロパゲーション)
③Cost Function(目的関数)
ロジスティック回帰における、正則化 (regularized) された目的関数は、以下のようでした。
https://gyazo.com/4b05b2d048062844ed1f0a5f883f6d94
ニューラルネットワークの目的関数は、ロジスティック回帰の繰り返しになります。このとき、$ L はネットワークのレイヤー数、$ s_l はレイヤー$ l のユニット数です。
https://gyazo.com/1f8726bac58c91d96731bd876525723c
④Backpropagation(バックプロパゲーション)
バックプロパゲーションは、ロジスティック回帰および線形回帰における勾配降下を行うときと同じように、コスト関数を最小化するためのものです。 つまり$ \frac{\partial}{\partial\Theta_{i, j}^{(l)}}J(\Theta) を計算することが目標です。
バックプロパゲーションのアルゴリズム
https://gyazo.com/4626ec29630914e9c05406c21fd026b8
バックプロパゲーションのアルゴリズムをより詳しく
アルゴリズムが複雑なので、いくつか手順に分けて考えてみたいと思います。
【前提として】
トレーニングデータ{$ (x^{(1)}, y^{(1)}), ..., (x^{(m)}, y^{(m)}) }が与えられているとします。
パラメーター$ \Delta_{i, j}^{(l)} := 0 を用意します。これには、目的関数$ J(\Theta) の偏微分値が入ります。最初は$ 0 でいっぱいの行列にしておきます。
【アルゴリズムでは、$ i=1,...,m において、以下のステップを繰り返します】
1. $ a^{(1)} := x^{(t)} とします。入力層がレイヤー1の層になるという意味です。
2. フォアワードプロパゲーションで、$ a^{(l)} $ (l = 2, 3, ..., L) を計算します。
https://gyazo.com/808b70e591f21b7252de8d7f8d7da9fa
3. 出力層$ a^{(L)} と実際のラベル$ y^{(t)} との誤差、$ \delta^{(L)} = a^{(L)} - y^{(t)} を計算します。
4. 各層の誤差、$ \delta^{(l)} = (\Theta^{(l)})^T\delta^{(l + 1)}.*g'(z^{(l)}) を計算します。
※ $ g'(z^{(l)}) = a^{(l)}.*(1 - a^{(l)})
5. 偏微分値をアップデートします。-> $ \Delta_{i, j}^{(l)} := \Delta_{i, j}^{(l)} + a_j^{(l)}\delta_i^{(l + 1)}
6. 最終的な偏微分値は、平均を取って正則化したもので、以下のようになります。
https://gyazo.com/c012b520e88cd43ae73ec29c91b63de2
したがって、$ \frac{\partial}{\partial\Theta_{i, j}^{(l)}}J(\Theta) = D_{i, j}^{(l)} となります。
⑤Gradient Checking
Gradient Checkingは、バックプロパゲーションが意図した通りに機能することを保証します。 コスト関数の導関数を次のように近似することができます。
https://gyazo.com/6a973704c53d5e92358dbce86685ece6
複数の行列の場合は、次のようにします。
https://gyazo.com/9ccdb33068573a1417ddcbba47d0e2fa
$ \epsilon は$ 10^{-4} くらい小さい値が妥当です。これより小さいと数値的な問題が発生する可能性があります。
code: Octave
epsilon = 1e-4;
for i = 1:n,
thetaPlus = theta;
thetaPlus(i) += epsilon;
thetaMinus = theta;
thetaMinus(i) -= epsilon;
gradApprox(i) = (J(thetaPlus) - J(thetaMinus))/(2*epsilon)
end;
Gradient Checkingは計算にとても時間がかかるため、確認出来たらコメントアウトか削除します。